home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr42 / smixc111.zip / SMIX.C < prev    next >
C/C++ Source or Header  |  1995-02-15  |  22KB  |  776 lines

  1. /*      SMIXC is Copyright 1995 by Ethan Brodsky.  All rights reserved      */
  2.  
  3. /* █ smix.c ███████████████████████████████████████████████████████████████ */
  4.  
  5. #define TRUE  1
  6. #define FALSE 0
  7.  
  8. #define ON  1
  9. #define OFF 0
  10.  
  11. #define BLOCK_LENGTH    256   /* Length of digitized sound output block     */
  12. #define LOAD_CHUNK_SIZE 2048  /* Chunk size used to load sounds from disk   */
  13. #define VOICES          8     /* Number of available simultaneous voices    */
  14.                               /* Change VOICES at your own risk             */
  15. typedef struct
  16.   {
  17.     int xmshandle;
  18.     long startofs;
  19.     long soundsize;
  20.   } SOUND;
  21.  
  22. int  init_sb(int baseio, int irq, int dma, int dma16);
  23.   /* Initializes control parameters, resets DSP and installs int. handler   */
  24.   /*  Parameters:                                                           */
  25.   /*   baseio    Sound card base IO address                                 */
  26.   /*   irq       Sound card IRQ setting                                     */
  27.   /*   dma       Sound card 8-bit DMA channel                               */
  28.   /*   dma16     Sound card 16-bit DMA channel                              */
  29.   /*  Returns:                                                              */
  30.   /*   TRUE      Sound card successfully initialized                        */
  31.   /*   FALSE     Sound card could not be initialized                        */
  32.  
  33. void shutdown_sb(void);
  34.   /* Removes interrupt handler and resets DSP                               */
  35.  
  36.  
  37. void init_mixing(void);
  38.   /* Allocates internal buffers and starts digitized sound output           */
  39.  
  40. void shutdown_mixing(void);
  41.   /* Deallocates internal buffers and stops digitized sound output          */
  42.  
  43.  
  44. int  init_xms(void);
  45.   /* Initializes extended memory driver                                     */
  46.   /*  Returns:                                                              */
  47.   /*   TRUE      Extended memory driver successfully initialized            */
  48.   /*   FALSE     Extended memory driver could not be initialized            */
  49.  
  50. int  getfreexms(void);
  51.   /* Returns amount of free extended memory (In kilobytes)                  */
  52.  
  53.  
  54. void init_sharing(void);
  55.   /* Allocates an EMB that all sound data will be stored in.  Using this    */
  56.   /* will preserve extended memory handles, which are scarce resources.     */
  57.   /* Call this on initialization and all sounds will automatically be       */
  58.   /* stored in one EMB.  You can call load_sound as usual to allocate a     */
  59.   /* sound, but free_sound will only deallocate the sound data structure.   */
  60.   /* You must call shutdown_sharing before program termination in order     */
  61.   /* to free all allocated extended memory.                                 */
  62.  
  63. void shutdown_sharing(void);
  64.   /* Shuts down EMB sharing and frees shared EMB block                      */
  65.  
  66.  
  67. void load_sound(SOUND **sound, char *filename);
  68.   /* Allocates an extended memory block and loads a sound from a file       */
  69.   /*  Parameters:                                                           */
  70.   /*   sound     Pointer to pointer to unallocated sound data structure     */
  71.   /*   filename  Pointer to character string containing filename            */
  72.  
  73. void free_sound(SOUND **sound);
  74.   /* Frees sound data structure and extended memory block                   */
  75.   /*  Parameters:                                                           */
  76.   /*   sound     Pointer to pointer to allocated sound data structure       */
  77.  
  78.  
  79. void start_sound(SOUND *sound, int index, int loop);
  80.   /* Starts playing a sound                                                 */
  81.   /*  Parameters:                                                           */
  82.   /*   sound     Pointer to sound data structure                            */
  83.   /*   index     A number to keep track of the sound with (Used to stop it) */
  84.   /*   loop      Indicates whether sound should be continuously looped      */
  85.  
  86. void stop_sound(int index);
  87.   /* Stops playing a sound                                                  */
  88.   /*  Parameters:                                                           */
  89.   /*   index     Index of sound to stop (All with given index are stopped)  */
  90.  
  91.  
  92. volatile long  intcount;       /* Current count of sound interrupts         */
  93. volatile float dspversion;     /* Version of the sound card DSP chip        */
  94. volatile int   voicecount;     /* Number of voices currently in use         */
  95.  
  96. int autoinit;
  97. int sixteenbit;
  98.  
  99. /* ████████████████████████████████████████████████████████████████████████ */
  100.  
  101. #include <alloc.h>
  102. #include <conio.h>
  103. #include <stdio.h>
  104. #include <stdlib.h>
  105. #include <dos.h>
  106. #include <mem.h>
  107.  
  108. #include "xms.h"
  109.  
  110. #define BUFFER_LENGTH BLOCK_LENGTH*2
  111.  
  112. #define BYTE unsigned char
  113.  
  114. #define lo(value) (unsigned char)((value) & 0x00FF)
  115. #define hi(value) (unsigned char)((value) >> 8)
  116.  
  117. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  118. #define MIN(a, b) (((a) > (b)) ? (b) : (a))
  119.  
  120. int resetport;
  121. int readport;
  122. int writeport;
  123. int pollport;
  124. int poll16port;
  125.  
  126. int pic_rotateport;
  127. int pic_maskport;
  128.  
  129. int dma_maskport;
  130. int dma_clrptrport;
  131. int dma_modeport;
  132. int dma_addrport;
  133. int dma_countport;
  134. int dma_pageport;
  135.  
  136. int irq_startmask;
  137. int irq_stopmask;
  138. int irq_intvector;
  139.  
  140. int dma_startmask;
  141. int dma_stopmask;
  142. int dma_mode;
  143.  
  144. int  shared_emb;
  145. int  shared_handle;
  146. long shared_size;
  147.  
  148. void (interrupt far *oldintvector)(void);
  149.  
  150. int handler_installed;
  151.  
  152. void write_dsp(BYTE value)
  153.   {
  154.     while ((inp(writeport) & 0x80));
  155.     outp(writeport, value);
  156.   }
  157.  
  158. BYTE read_dsp(void)
  159.   {
  160.     while (!(inp(pollport) & 0x80));
  161.     return(inp(readport));
  162.   }
  163.  
  164. int reset_dsp(void)
  165.   {
  166.     int i;
  167.  
  168.     outp(resetport, 1);
  169.     outp(resetport, 0);
  170.     i = 100;
  171.     while ((read_dsp() != 0xAA) && i--);
  172.     return(i);
  173.   }
  174.  
  175. void install_handler(void);
  176. void uninstall_handler(void);
  177. void mix_exitproc(void);
  178.  
  179. int init_sb(int baseio, int irq, int dma, int dma16)
  180.   {
  181.    /* Sound card IO ports */
  182.     resetport  = baseio + 0x006;
  183.     readport   = baseio + 0x00A;
  184.     writeport  = baseio + 0x00C;
  185.     pollport   = baseio + 0x00E;
  186.     poll16port = baseio + 0x00F;
  187.  
  188.    /* Reset DSP, get version, choose output mode */
  189.     if (!reset_dsp())
  190.       return(0);
  191.     write_dsp(0xE1);  /* Get DSP version number */
  192.     dspversion = read_dsp();  dspversion += read_dsp() / 100.0;
  193.     autoinit   = (dspversion > 2.0);
  194.     sixteenbit = (dspversion > 4.0) && dma16;
  195.  
  196.    /* Compute interrupt controller ports and parameters */
  197.     if (irq < 8)
  198.       { /* PIC1 */
  199.         irq_intvector  = 0x08 + irq;
  200.         pic_rotateport = 0x20;
  201.         pic_maskport   = 0x21;
  202.       }
  203.     else
  204.       { /* PIC2 */
  205.         irq_intvector  = 0x70 + irq-8;
  206.         pic_rotateport = 0xA0;
  207.         pic_maskport   = 0xA1;
  208.       }
  209.     irq_stopmask  = 1 << (irq % 8);
  210.     irq_startmask = ~irq_stopmask;
  211.  
  212.    /* Compute DMA controller ports and parameters */
  213.     if (sixteenbit)
  214.       { /* Sixteen bit */
  215.         dma_maskport   = 0xD4;
  216.         dma_clrptrport = 0xD8;
  217.         dma_modeport   = 0xD6;
  218.         dma_addrport   = 0xC0 + 4*(dma16-4);
  219.         dma_countport  = 0xC2 + 4*(dma16-4);
  220.         switch (dma16)
  221.           {
  222.             case 5:
  223.               dma_pageport = 0x8B;
  224.               break;
  225.             case 6:
  226.               dma_pageport = 0x89;
  227.               break;
  228.             case 7:
  229.               dma_pageport = 0x8A;
  230.               break;
  231.           }
  232.         dma_stopmask  = dma16-4 + 0x04;  /* 000001xx */
  233.         dma_startmask = dma16-4 + 0x00;  /* 000000xx */
  234.         if (autoinit)
  235.           dma_mode = dma16-4 + 0x58;     /* 010110xx */
  236.         else
  237.           dma_mode = dma16-4 + 0x48;     /* 010010xx */
  238.       }
  239.     else
  240.       { /* Eight bit */
  241.         dma_maskport   = 0x0A;
  242.         dma_clrptrport = 0x0C;
  243.         dma_modeport   = 0x0B;
  244.         dma_addrport   = 0x00 + 2*dma;
  245.         dma_countport  = 0x01 + 2*dma;
  246.         switch (dma)
  247.           {
  248.             case 0:
  249.               dma_pageport = 0x87;
  250.               break;
  251.             case 1:
  252.               dma_pageport = 0x83;
  253.               break;
  254.             case 2:
  255.               dma_pageport = 0x81;
  256.               break;
  257.             case 3:
  258.               dma_pageport = 0x82;
  259.               break;
  260.           }
  261.         dma_stopmask  = dma + 0x04;      /* 000001xx */
  262.         dma_startmask = dma + 0x00;      /* 000000xx */
  263.         if (autoinit)
  264.           dma_mode    = dma + 0x58;      /* 010110xx */
  265.         else
  266.           dma_mode    = dma + 0x48;      /* 010010xx */
  267.       }
  268.     install_handler();
  269.     shared_emb = FALSE;
  270.     atexit(mix_exitproc);
  271.  
  272.     return(1);
  273.   }
  274.  
  275. void shutdown_sb(void)
  276.   {
  277.     uninstall_handler();
  278.     reset_dsp();
  279.   }
  280.  
  281. int init_xms(void)
  282.   {
  283.     xms_init();
  284.     return(xms_installed());
  285.   }
  286.  
  287. int getfreexms(void)
  288.   {
  289.     return(xms_getfreemem());
  290.   }
  291.  
  292. /* Voice control */
  293. typedef struct
  294.   {
  295.     SOUND *sound;
  296.     int   index;
  297.     long  curpos;
  298.     int   loop;
  299.   } VOICE;
  300.  
  301. int   inuse[VOICES];
  302. VOICE voice[VOICES];
  303.  
  304. /* Sound buffer */
  305.  
  306. signed char soundblock[BLOCK_LENGTH]; /* Signed 8 bit */
  307.  
  308. /* Mixing buffer */
  309.  
  310. short int mixingblock[BLOCK_LENGTH];  /* Signed 16 bit */
  311.  
  312. /* Output buffers */
  313.  
  314. void *outmemarea = NULL;
  315. unsigned char (*out8buf)[2][BLOCK_LENGTH]  = NULL;  /* Unsigned 8 bit */
  316. short int     (*out16buf)[2][BLOCK_LENGTH] = NULL;  /* Signed 16 bit  */
  317.  
  318. int curblock;
  319. void *blockptr[2];
  320. void *curblockptr;
  321.  
  322. /* Addressing for auto-initialized transfers (Whole buffer) */
  323. unsigned long buffer_addr;
  324. unsigned char buffer_page;
  325. unsigned int  buffer_ofs;
  326.  
  327. /* Addressing for single-cycle transfers (One block at a time */
  328. unsigned long block_addr[2];
  329. unsigned char block_page[2];
  330. unsigned int  block_ofs[2];
  331.  
  332. int handler_installed;
  333.  
  334. void start_dac(void)
  335.   {
  336.     if (autoinit)
  337.       { /* Auto init DMA */
  338.         outp(dma_maskport,   dma_stopmask);
  339.         outp(dma_clrptrport, 0x00);
  340.         outp(dma_modeport,   dma_mode);
  341.         outp(dma_addrport,   lo(buffer_ofs));
  342.         outp(dma_addrport,   hi(buffer_ofs));
  343.         outp(dma_countport,  lo(BUFFER_LENGTH-1));
  344.         outp(dma_countport,  hi(BUFFER_LENGTH-1));
  345.         outp(dma_pageport,   buffer_page);
  346.         outp(dma_maskport,   dma_startmask);
  347.       }
  348.     else
  349.       { /* Single cycle DMA */
  350.         outp(dma_maskport,   dma_stopmask);
  351.         outp(dma_clrptrport, 0x00);
  352.         outp(dma_modeport,   dma_mode);
  353.         outp(dma_addrport,   lo(buffer_ofs));
  354.         outp(dma_addrport,   hi(buffer_ofs));
  355.         outp(dma_countport,  lo(BLOCK_LENGTH-1));
  356.         outp(dma_countport,  hi(BLOCK_LENGTH-1));
  357.         outp(dma_pageport,   buffer_page);
  358.         outp(dma_maskport,   dma_startmask);
  359.       }
  360.  
  361.     if (sixteenbit)
  362.       { /* Sixteen bit auto-initialized: SB16 and up (DSP 4.xx)             */
  363.         write_dsp(0x41);                /* Set sound output sampling rate   */
  364.         write_dsp(hi(22050));
  365.         write_dsp(lo(22050));
  366.         write_dsp(0xB6);                /* 16-bit cmd  - D/A - A/I - FIFO   */
  367.         write_dsp(0x10);                /* 16-bit mode - signed mono        */
  368.         write_dsp(lo(BLOCK_LENGTH-1));
  369.         write_dsp(hi(BLOCK_LENGTH-1));
  370.       }
  371.     else
  372.       { /* Eight bit */
  373.         if (autoinit)
  374.           { /* Eight bit auto-initialized:  SBPro and up (DSP 2.00+)        */
  375.             write_dsp(0xD1);            /* Turn on speaker                  */
  376.             write_dsp(0x40);            /* Set sound output time constant   */
  377.             write_dsp(211);             /*  = 256 - (1000000 / rate)        */
  378.             write_dsp(0x48);            /* Set DSP block transfer size      */
  379.             write_dsp(lo(BLOCK_LENGTH-1));
  380.             write_dsp(hi(BLOCK_LENGTH-1));
  381.             write_dsp(0x1C);            /* 8-bit auto-init DMA mono output  */
  382.           }
  383.         else
  384.           { /* Eight bit single-cycle:  Sound Blaster (DSP 1.xx+)           */
  385.             write_dsp(0xD1);            /* Turn on speaker                  */
  386.             write_dsp(0x40);            /* Set sound output time constant   */
  387.             write_dsp(211);             /*  = 256 - (1000000 / rate)        */
  388.             write_dsp(0x14);            /* 8-bit single-cycle DMA output    */
  389.             write_dsp(lo(BLOCK_LENGTH-1));
  390.             write_dsp(hi(BLOCK_LENGTH-1));
  391.           }
  392.       }
  393.   }
  394.  
  395. void stop_dac(void)
  396.   {
  397.     if (sixteenbit)
  398.       {
  399.         write_dsp(0xD5);                /* Pause 16-bit DMA sound I/O       */
  400.       }
  401.     else
  402.       {
  403.         write_dsp(0xD0);                /* Pause 8-bit DMA sound I/O        */
  404.         write_dsp(0xD3);                /* Turn off speaker                 */
  405.       }
  406.   }
  407.  
  408.  
  409. /* Setup for storinng all sounds in one EMB (Saves handles) */
  410.  
  411. void init_sharing(void)
  412.   {
  413.     shared_emb = TRUE;
  414.     xms_allocate(&shared_handle, (shared_size = 0));
  415.   }
  416.  
  417. void shutdown_sharing(void)
  418.   {
  419.     if (shared_emb) xms_free(&shared_handle);
  420.     shared_emb    = FALSE;
  421.     shared_handle = 0;
  422.     shared_size   = 0;
  423.   }
  424.  
  425. /* Loading and freeing sounds */
  426.  
  427.  
  428. void load_sound(SOUND **sound, char *filename)
  429.   {
  430.     FILE *f;
  431.     long size;
  432.     char inbuf[LOAD_CHUNK_SIZE];
  433.     long insize;
  434.     static MOVEPARAMS moveparams;
  435.  
  436.     f = fopen(filename, "rb");
  437.     fseek(f, 0, SEEK_END); /* Move to end of file */
  438.     size = ftell(f);       /* File size = end pos */
  439.     fseek(f, 0, SEEK_SET); /* Back to begining    */
  440.  
  441.     *sound = (SOUND *)malloc(sizeof(SOUND));
  442.  
  443.     (*sound)->soundsize = size;
  444.  
  445.     if (!shared_emb)
  446.       {
  447.         (*sound)->startofs = 0;
  448.         xms_allocate(&((*sound)->xmshandle), (size / 1024) + 1);
  449.       }
  450.     else
  451.       {
  452.         (*sound)->startofs  = shared_size;
  453.         (*sound)->xmshandle = shared_handle;
  454.         shared_size += size;
  455.         xms_reallocate(shared_handle, (shared_size / 1024) + 1);
  456.       }
  457.  
  458.     moveparams.sourcehandle = 0;
  459.     moveparams.sourceoffset = (long)(&inbuf);
  460.     moveparams.desthandle   = (*sound)->xmshandle;
  461.     moveparams.destoffset   = (*sound)->startofs;
  462.  
  463.     do
  464.       {
  465.         moveparams.length = insize = fread(&inbuf, 1, sizeof(inbuf), f);
  466.         xms_move(&moveparams);
  467.         moveparams.destoffset += insize;
  468.       }
  469.     while (insize);
  470.   }
  471.  
  472. void free_sound(SOUND **sound)
  473.   {
  474.     if (!shared_emb) xms_free(&((*sound)->xmshandle));
  475.     free(*sound);
  476.     *sound = NULL;
  477.   }
  478.  
  479. /* Voice maintainance */
  480.  
  481. void deallocate_voice(int voicenum)
  482.   {
  483.     inuse[voicenum] = FALSE;
  484.     voice[voicenum].sound  = NULL;
  485.     voice[voicenum].index  = 0;
  486.     voice[voicenum].curpos = 0;
  487.     voice[voicenum].loop   = 0;
  488.   }
  489.  
  490. void start_sound(SOUND *sound, int index, int loop)
  491.   {
  492.     int i, slot;
  493.     slot = -1; i = 0;
  494.     do
  495.       {
  496.         if (!inuse[i])
  497.           slot = i;
  498.         i++;
  499.       }
  500.     while ((slot == -1) && (i < VOICES));
  501.     if (slot != -1)
  502.       {
  503.         voice[slot].sound  = sound;
  504.         voice[slot].index  = index;
  505.         voice[slot].curpos = 0;
  506.         voice[slot].loop   = loop;
  507.  
  508.         inuse[slot] = TRUE;
  509.  
  510.         ++voicecount;
  511.         inuse[slot] = TRUE;
  512.       }
  513.   }
  514.  
  515. void stop_sound(int index)
  516.   {
  517.     int i;
  518.     for (i=0; i < VOICES; i++)
  519.       if (voice[i].index == index)
  520.         {
  521.           deallocate_voice(i);
  522.           --voicecount;
  523.         }
  524.   }
  525.  
  526. void update_voices(void)
  527.   {
  528.     int voicenum;
  529.  
  530.     for (voicenum=0; voicenum < VOICES; voicenum++)
  531.       {
  532.         if (inuse[voicenum])
  533.           {
  534.             if (voice[voicenum].curpos >= voice[voicenum].sound->soundsize)
  535.               {
  536.                 deallocate_voice(voicenum);
  537.                 --voicecount;
  538.               }
  539.           }
  540.       }
  541.   }
  542.  
  543. /* Utility functions */
  544.  
  545. void setcurblock(int blocknum)
  546.   {
  547.     curblockptr = blockptr[(curblock = blocknum)];
  548.   }
  549.  
  550. void silenceblock(void)
  551.   {
  552.     memset(&mixingblock, 0x00, BLOCK_LENGTH*2);
  553.   }
  554.  
  555. long getlinearaddr(void far *ptr)
  556.   {
  557.     return((long)FP_SEG(ptr)*16 + (long)FP_OFF(ptr));
  558.   }
  559.  
  560. void init_mixing(void)
  561.   {
  562.     int i;
  563.  
  564.     for (i=0; i < VOICES; deallocate_voice(i++));
  565.     voicecount = 0;
  566.  
  567.     if (sixteenbit)
  568.       {
  569.        /* Find a block of memory that does not cross a page boundary */
  570.         outmemarea = malloc(4*BUFFER_LENGTH);
  571.         out16buf = outmemarea;
  572.         if ((((getlinearaddr(outmemarea) >> 1) % 65536) + BUFFER_LENGTH) > 65536)
  573.           out16buf += BUFFER_LENGTH;
  574.         for (i=0; i<2; i++) blockptr[i] = (void *)&((*out16buf)[i]);
  575.  
  576.        /* DMA parameters */
  577.         buffer_addr = getlinearaddr(out16buf);
  578.         buffer_page = buffer_addr >> 16;
  579.         buffer_ofs  = (buffer_addr >> 1) % 65536;
  580.       }
  581.     else
  582.       {
  583.        /* Find a block of memory that does not cross a page boundary */
  584.         outmemarea = malloc(2*BUFFER_LENGTH);
  585.         out8buf = outmemarea;
  586.         if (((getlinearaddr(outmemarea) % 65536) + BUFFER_LENGTH) > 65536)
  587.           out8buf += BUFFER_LENGTH;
  588.         for (i=0; i<2; i++) blockptr[i] = (void *)&((*out8buf)[i]);
  589.  
  590.        /* DMA parameters */
  591.         buffer_addr = getlinearaddr(out8buf);
  592.         buffer_page = buffer_addr / 65536;
  593.         buffer_ofs  = buffer_addr % 65536;
  594.         for (i=0; i<2; i++)
  595.           {
  596.             block_addr[i] = getlinearaddr(blockptr[i]);
  597.             block_page[i] = block_addr[i] / 65536;
  598.             block_ofs[i]  = block_addr[i]  % 65536;
  599.           }
  600.       }
  601.     if (sixteenbit)
  602.       memset((void *)out16buf, 0x00, BUFFER_LENGTH*2); /* Signed 16-bit  */
  603.     else
  604.       memset((void *)out8buf, 0x80, BUFFER_LENGTH);    /* Unsigned 8-bit */
  605.     setcurblock(0);
  606.     intcount = 0;
  607.     start_dac();
  608.   }
  609.  
  610. void shutdown_mixing(void)
  611.   {
  612.     stop_dac();
  613.     free((void *)outmemarea);
  614.   }
  615.  
  616. void copy_sound(SOUND *sound, long *curpos, int copylength, int loop)
  617.   {
  618.     long soundsize;
  619.     char far *destptr;
  620.     static MOVEPARAMS moveparams;
  621.  
  622.     soundsize = sound->soundsize;
  623.     destptr   = (char far *)(&soundblock);
  624.     moveparams.sourcehandle = sound->xmshandle;
  625.     moveparams.desthandle   = 0;
  626.     do
  627.       {
  628.        /* Compute transfer size */
  629.         moveparams.length = min(copylength, soundsize - (*curpos));
  630.  
  631.        /* Compute starting source offset and update offset for next block */
  632.         moveparams.sourceoffset = sound->startofs + (*curpos);
  633.         (*curpos) += moveparams.length;
  634.         if (loop) (*curpos) %= soundsize;
  635.  
  636.        /* Compute starting dest offset and update offset for next block */
  637.         moveparams.destoffset = (long)destptr;
  638.         destptr += moveparams.length;
  639.  
  640.        /* Update remaining count for next iteration (If any) */
  641.         copylength -= moveparams.length;
  642.  
  643.        /* Copy block down from extended memory */
  644.         xms_move(&moveparams);  /* Luckily, the XMS driver is re-entrant */
  645.       }
  646.     while (copylength > 0);
  647.   }
  648.  
  649. void mix_voice(VOICE *voice)
  650.   {
  651.     int i;
  652.  
  653.     int mixlength;
  654.  
  655.     if (voice->loop)
  656.       mixlength = BLOCK_LENGTH;
  657.     else
  658.       mixlength = MIN(BLOCK_LENGTH, voice->sound->soundsize - voice->curpos);
  659.     copy_sound(voice->sound, &(voice->curpos), mixlength, voice->loop);
  660.  
  661.     for (i=0; i < BLOCK_LENGTH; i++)
  662.       mixingblock[i] += soundblock[i];
  663.   }
  664.  
  665. void expand_range(void)
  666.   {
  667.     int i;
  668.  
  669.     for (i=0; i < BLOCK_LENGTH; i++)
  670.       mixingblock[i] <<= 5;         
  671.   }
  672.  
  673. void mix_voices(void)
  674.   {
  675.     int i;
  676.  
  677.     silenceblock();
  678.     for (i=0; i < VOICES; i++)
  679.       if (inuse[i]) mix_voice(&(voice[i]));
  680.     expand_range();
  681.   }
  682.  
  683. void condense16to8(void)
  684.   {
  685.     unsigned char *outptr;
  686.     int i;
  687.  
  688.     outptr = &((*out8buf)[curblock][0]);
  689.     for (i=0; i < BLOCK_LENGTH; i++)
  690.       *outptr++ = (mixingblock[i] >> 8) + 0x80;
  691.   }
  692.  
  693. void copydata(void)
  694.   {
  695.     if (sixteenbit)
  696.       movmem(mixingblock, curblockptr, BLOCK_LENGTH*2);
  697.     else
  698.       condense16to8();
  699.   }
  700.  
  701. void startblock_sc(void) /* Starts a single-cycle DMA transfer */
  702.   {
  703.     outp(dma_maskport,   dma_stopmask);
  704.     outp(dma_clrptrport, 0x00);
  705.     outp(dma_modeport,   dma_mode);
  706.     outp(dma_addrport,   lo(block_ofs[curblock]));
  707.     outp(dma_addrport,   hi(block_ofs[curblock]));
  708.     outp(dma_countport,  lo(BLOCK_LENGTH-1));
  709.     outp(dma_countport,  hi(BLOCK_LENGTH-1));
  710.     outp(dma_pageport,   block_page[curblock]);
  711.     outp(dma_maskport,   dma_startmask);
  712.     write_dsp(0x14);                /* 8-bit single-cycle DMA sound output  */
  713.     write_dsp(lo(BLOCK_LENGTH-1));
  714.     write_dsp(hi(BLOCK_LENGTH-1));
  715.   }
  716.  
  717. void interrupt inthandler(void)
  718.   {
  719.     if (!autoinit)  /* Start next block first if not using auto-init DMA */
  720.       {
  721.         startblock_sc();
  722.         copydata();
  723.         setcurblock(!curblock); /* Toggle block */
  724.       }
  725.  
  726.     update_voices();
  727.     mix_voices();
  728.  
  729.     if (autoinit)
  730.       {
  731.         copydata();
  732.         setcurblock(!curblock); /* Toggle block */
  733.       }
  734.  
  735.     ++intcount;
  736.     if (sixteenbit)    /* Acknowledge interrupt with sound card */
  737.       inp(poll16port); /*  16-bit */
  738.     else
  739.       inp(pollport);   /*  8-bit  */
  740.  
  741.     outp(0x20, 0x20);  /* Acknowledge interrupt with PIC1 */
  742.     outp(0xA0, 0x20);  /* Acknowledge interrupt with PIC2 */
  743.   }
  744.  
  745. void install_handler(void)
  746.   {
  747.     disable();
  748.     outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  749.  
  750.     oldintvector = _dos_getvect(irq_intvector);
  751.     _dos_setvect(irq_intvector, inthandler);
  752.  
  753.     outp(pic_maskport, (inp(pic_maskport) & irq_startmask));
  754.     enable();
  755.  
  756.     handler_installed = TRUE;
  757.   }
  758.  
  759. void uninstall_handler(void)
  760.   {
  761.       disable();
  762.       outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  763.  
  764.       _dos_setvect(irq_intvector, oldintvector);
  765.  
  766.       enable();
  767.  
  768.       handler_installed = FALSE;
  769.   }
  770.  
  771. void mix_exitproc(void)
  772.   {
  773.     outp(dma_maskport, dma_stopmask);
  774.     if (handler_installed) uninstall_handler();
  775.   }
  776.